到目前為止,無論是把一換一(smcp, vert, calt, swsh, ss01)或是多換一(liga, hlig, dlig),都是「字符」對「字符」之間的變化——那如果是「變音符號(Diacritic)」與「字符」呢?
依舊拿法文和德文來舉例,像是有一撇(尖音符,Acute)的 é
和有兩點(元音變化符,Umlaut)的 ü
又該怎麼處理?
在原始的 ASCII,也就是英文字母裡,是不存在這些變音符號的(至於為什麼在英文裡沒有使用變音字母呢?這可是另一個語言學的大問題),但隨著編碼的擴充,為了配合不同的語言需求,便在拉丁字母擴展區中塞入了不同的變音字母,例如上面提到的 é
或是 ü
。
不過,Unicode 很快就意識到,收錄所有變音字母的想法實在太過天真,畢竟變音符號這種在任合字母上都可以加上去的東西,有時候還不僅限於只加一個,有需要的話可以無限的上疊,產出的組合可以説成千上萬——光是一個 a
,就 至少 可以組出 áăắặằẳẵǎâấậầẩẫäạàảāąåǻã
共 23 種變化——甚至,你也可以在漢字上面標記變音字母,雖然沒有人會這樣,但也沒規定不行這樣做。
因此,Unicode 在 U+0300
- U+036F
區域預作變音符號,允許任意字母和這一區的變音符號進行組合。
這一區的變音符號除了上面提及的拉丁字母之外,也收錄了希臘字母的變音符號、日文的濁點與半濁點、希伯來文的尼庫德(Niqqud)記號等。
透過 ccmp,我們便可以「製作」出沒有被收錄在 Unicode 裡面的變音字母,例如台羅拼音的第八調調號字符。因此,ccmp 也是一種替換。
通常來說,軟體與瀏覽器會強制使用 ccmp,只要有好好設定(言外之意就是很多字型其實都沒有正確的設定),字符與變音符號就能透過該表進行「合體」。
.class {
-moz-font-feature-settings: "ccmp";
-webkit-font-feature-settings: "ccmp";
font-feature-settings: "ccmp";
}
但為了讓那些不支援 OpneType 的陽春文書軟體亦能正常顯示,變音符號的字符寬度通常會設為 0,讓變音符號可以和字符相貼在一起。即使沒辦法讓變音符號出現在正確的位置,但至少可以大致上知道該字是一個變音字母,不至於造成歧異。
此外,變音符號的使用不僅限於一個,每次組合起來的變音字母都可以在和新的變音符號再組合,理論上,是可以無限添加在子母上的。有時候會在網路上看到像是 「Ȟ͙̰̜̠͚̈̀̈̓̋̀̾̐e̱͔̝̞̬̘̩̽̋͋̑̀̌̆͊̐̋l̝̝͕̦͇̪͚̱͙̲̠̦͊̆̋́̇l̰̥̞͓͙͇̬̦̽̃̐͂̒̿͊̒͊̃̌̾ǒ͎̞̰̝̬̥͎̝̞͔̖̏͊͛̊͂̀̆͗͛͗̄ W̖̗̬͓̤͚̞̋́͊͆̇̇͑̓̈̾̚ͅo̳̲̤̩̭͇̓́̏̎̀r̥̣͓͍̊́̏̾̾́̌̐d͓̰̥̠͕͉͇̜̝́̎͌̉̾̈́̉ͅ」這樣的迷惑字母(稱作 Zalgo),就是運用了符號組合的 ccmp。
在現代韓文字母(Hangul Jamo)中,共有 19 個初聲(자음,子音)、21 個中聲(모음,母音)、28 個終聲(종성,27 個子音組合以及「沒有」),排列組合之後總共有 192128 = 11,172 種可能。
在這 11,172 個字母組合中,又有許多發音饒舌、結構奇葩的韓文是不會使用到的,實際生活中大概只會看到 1,200 多種字母。舉例來説,빪
[ppal] 應該已經是目前正在使用的韓文裡最複雜的了(빨다 - 「洗」的名詞形);更複雜的像是 쬂
[jjwaelt] (我也不會念),就只是在拼字邏輯上合理、但現實生活不可能用到的字。
面對這 11,172 的組合,如果使用 ccmp 實現組合,便只需要佔用 19+21+28=68 個碼位就好,那為何 Unicode 還是為每個可能出現的韓文都分配了單獨的碼位?雖然有謎之八卦指出是韓國的施壓,但我想還是為了配合當初韓國廠商施行已久的 KS X 1001 編碼、以及當年 OpenType 支援度還未普及的關係。
在歷史上,1991 年最初釋出的 Unicode 1.0 中,在 U+3400
- U+3D2D
區域收錄了 2350 個常見韓文、隔年 1.1 又再增加 4306 個韓文(佔用 U+3400
- U+4DFF
)。這個時間點剛好是 OpenType 剛誕生的時候,對組合的支援性還未普及,因此 Unicode 最後還是決定獨立收錄所有組合結果。於是,在 1993 年 的 2.0 版本中,韓文被搬遷到 U+AC00
- U+D7AF
區域。原本的碼位改收錄 CJK 擴充 A 和易經八卦符號——這也是為何擴 A 的碼位會比基本區還前面的原因,也是 Unicode 極少更改碼位的事件。
當然,這不代表我們不能用 ccmp 來組韓文,如果你瀏覽器的字型(像是思源系列)有支援 OpenType ccmp 的話,각
(U+AC01
)和 각
(U+1100
/ U+1161
/ U+11A8
)看起來就 應該要是一樣的。反之,若你看到後面的 [gag] 是三個字母,就代表你的字型並沒有特別映射 ccmp。
至於更複雜,至多包含 124 個初聲、94 個中聲、137 個終聲、2 個旁點,理論上可以同時合併九個部件,多達 1,638,750 種組合可能的古韓文與方言...恩...面對連 Unicode 都放不下的數量,就只能先使用 ccmp 組合、再使用 Unicode 裡額外的 ljmo (Leading consonant Jamo)、vjmo (vowel Jamo) 和 tjmo (trailing Jamo) 特性顯示了——其中大多的結果只是為了展現韓文的組合邏輯和可組合性,歷史上根本不會使用到。
目前,因為我們已經可以透過變音符號區自由的組合出字母,因此 Unicode 已經明確的表示不會再收錄新的變音字母。不過,那些在早期已經收錄的字母,因為 Unicode 原則的 Stability,其碼位也不會被移除。
此時,就有可能遇到一個問題,在早期被收錄在 Unicode 裡面的變音字母,例如 é
(U+00E9
),其實也可以透過組合的方式,以 e
(U+0065
)與 U+0301
來表示。雖然兩者「看起來」是一樣的,但記憶體裡儲存的碼位其實是不同的。
因此,若要執行搜尋與比對,和前面提到的未統一漢字相同,必須要將兩者透過正規化方法進行整併。